<html>
  <head></head>
  <body>
    <div>
      <p>监听树组</p>
    </div>
    <script>
      // Array的原型
      const arrayProto = Array.prototype

      // 数组原型代理商
      const arrayMethods = Object.create(arrayProto)

      // 可以改变数组自身的7个方法
      const methodsToPatch = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']

      // 劫持 数组原型代理商的7个方法
      methodsToPatch.forEach(method => {
        // 缓存原生数组方法
        const original = arrayProto[method]

        // def使用Object.defineProperty重新定义属性
        def(arrayMethods, method, function mutator(...args) {
          console.log('this', this)
          console.log('args', args)

          // 调用原生数组的方法
          const result = original.apply(this, args)

          console.log('result', result)
          console.log('执行视图更新操作！')

          // 通知所有订阅者触发回调的代码 可参考：https://vue3js.cn/es6/#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8proxy%E9%87%8D%E6%9E%84
          // ...
          // ...
          // ...
          return result
        })
      })

      // defineProperty 数据劫持方法
      function def(obj, key, fn) {
        Object.defineProperty(obj, key, {
          writable: true,
          enumerable: true,
          configurable: true,
          value: fn,
        })
      }

      // 原型的赋值
      function protoAugment(source, target) {
        source.__proto__ = target
      }

      const list = [1, 2, 3, 4]

      // 将数组的原型 链接到 中间代理商的原型上
      // vue 初始化的时候 递归遍历 data 对象的各个属性， 对数组执行 protoAugment 方法
      protoAugment(list, arrayMethods)

      list.sort((a, b) => b - a)
    </script>
  </body>
</html>
